<?php

namespace App\Http\Controllers;

use App\Events\OrderPaid;
use App\Exceptions\InvalidRequestException;
use App\Models\Order;
use Carbon\Carbon;
use Illuminate\Http\Request;

class PaymentController extends Controller
{
    /**
     * 支付宝支付
     *
     * @param Request $request
     * @param Order $order
     * @return mixed
     * @throws InvalidRequestException
     * @throws \Illuminate\Auth\Access\AuthorizationException
     */
    public function payByAlipay(Request $request, Order $order)
    {
        // 判断当前订单是否属于当前用户
        $this->authorize('own', $order);

        // 订单已支付或已关闭
        if ($order->paid_at || $order->closed){
            throw new InvalidRequestException('订单状态不正确');
        }

        // 调用支付宝的网页支付
        return app('alipay')->web([
            'out_trade_no' => $order->no, // 订单编号，需保证在商户端不重复
            'total_amount' => $order->total_amount, // 订单金额，单位元，支持小数点后两位
            'subject' => '支付 Laravel Shop 的订单：'.$order->no, // 订单标题
        ]);
    }

    /**
     * 支付宝前端回调页面
     */
    public function alipayReturn()
    {
        try{
            // 检验提交的参数是否合法
            app('alipay')->verify();
        }catch(\Exception $e){
            return view('pages.error', ['msg' => '数据不正确']);
        }
        return view('pages.success', ['msg' => '付款成功']);
    }

    /**
     * 支付宝后端回调
     */
    public function alipayNotify()
    {
        try{
            $data = app('alipay')->verify();
            $order = Order::where('no', $data->out_trade_no)->first();
            if (!$order){
                return 'fail';
            }

            // 订单是否已支付
            if ($order->paid_at){
                return app('alipay')->success();
            }

            $order->update([
                'paid_at' => Carbon::now(), // 支付时间
                'payment_method' => 'alipay', // 支付方式
                'payment_no' => $data->trade_no, // 支付宝订单号
            ]);

            event(new OrderPaid($order));
            return app('alipay')->success();
        }catch(\Exception $e){
            return 'fail';
        }
    }
}
